using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;

namespace Terra.Core.Common.Utils;

/// <summary>
/// 树形结构工具类
/// </summary>
public static class TreeUtils
{
    /// <summary>
    /// 将列表转换为树形结构
    /// </summary>
    /// <typeparam name="T">实体类型</typeparam>
    /// <typeparam name="TKey">主键类型</typeparam>
    /// <param name="items">列表数据</param>
    /// <param name="idSelector">ID选择器</param>
    /// <param name="parentIdSelector">父ID选择器</param>
    /// <param name="childrenSelector">子节点选择器</param>
    /// <param name="rootCondition">根节点条件，默认为父ID为null或默认值</param>
    /// <returns>树形结构列表</returns>
    public static List<T> BuildTree<T, TKey>(
        IEnumerable<T> items,
        Func<T, TKey> idSelector,
        Func<T, TKey> parentIdSelector,
        Func<T, IList<T>> childrenSelector,
        Func<T, bool> rootCondition = null)
    {
        if (items == null || !items.Any())
        {
            return new List<T>();
        }

        var allItems = items.ToList();

        // 确定根节点的条件
        rootCondition ??= item =>
            parentIdSelector(item) == null ||
            EqualityComparer<TKey>.Default.Equals(parentIdSelector(item), default);

        // 获取根节点
        var roots = allItems.Where(rootCondition).ToList();

        // 递归构建树
        var itemDict = allItems.ToDictionary(idSelector);

        foreach (var item in allItems)
        {
            var parentId = parentIdSelector(item);
            if (parentId != null && !EqualityComparer<TKey>.Default.Equals(parentId, default) &&
                itemDict.TryGetValue(parentId, out var parent))
            {
                var children = childrenSelector(parent);
                if (children == null)
                {
                    throw new InvalidOperationException($"The children collection is null for item with id {idSelector(parent)}");
                }

                if (!children.Contains(item))
                {
                    children.Add(item);
                }
            }
        }

        return roots;
    }

    /// <summary>
    /// 将列表转换为树形结构（使用泛型类型推断简化调用）
    /// </summary>
    /// <typeparam name="T">实体类型，必须包含Id和ParentId属性，以及Children集合</typeparam>
    /// <typeparam name="TKey">主键类型</typeparam>
    /// <param name="items">列表数据</param>
    /// <param name="idSelector">ID选择器</param>
    /// <param name="parentIdSelector">父ID选择器</param>
    /// <param name="rootParentId">根节点的父ID值，默认为null</param>
    /// <returns>树形结构列表</returns>
    public static List<T> ToTree<T, TKey>(
        this IEnumerable<T> items,
        Func<T, TKey> idSelector,
        Func<T, TKey> parentIdSelector,
        TKey rootParentId = default)
        where T : class
    {
        if (items == null || !items.Any())
        {
            return new List<T>();
        }

        var allItems = items.ToList();
        var lookup = allItems.ToLookup(parentIdSelector);
        Func<TKey, List<T>> getChildren = null;

        getChildren = parentId =>
        {
            var children = lookup[parentId].ToList();
            foreach (var item in children)
            {
                // 使用反射获取或创建Children属性值
                var childrenProperty = typeof(T).GetProperty("Children");
                if (childrenProperty != null)
                {
                    var childrenValue = getChildren(idSelector(item));
                    childrenProperty.SetValue(item, childrenValue);
                }
            }
            return children;
        };

        return getChildren(rootParentId);
    }
}